//
//  MyDocument.m
//  Book Editor
//
//  Created by Chris Karr on 6/20/08.
//  Copyright Northwestern University 2008 . All rights reserved.
//

#import "BookDocument.h"

#define SUMMARY_FIELD_WIDTH 254
#define ROW_HEIGHT 14

@implementation BookDocument

@synthesize book;
@synthesize published;
@synthesize started;
@synthesize finished;

@synthesize contributorsLabel;
@synthesize genresLabel;
@synthesize keywordsLabel;
@synthesize statusLabel;

@synthesize contributors;
@synthesize genres;
@synthesize keywords;
@synthesize status;

@synthesize coverBox;
@synthesize firstLine;

@synthesize tabs;

@synthesize fileDictionary;

- (id) init 
{
    if (self = [super init]) 
	{
		self.fileDictionary = [NSMutableDictionary dictionary];
    }
	
    return self;
}

- (NSString *) displayName
{
	NSURL * url = [self fileURL];
	
	NSString * title = [self.book valueForKey:@"title"];
	
	if (url != nil && [[url path] hasSuffix:DATAFILE])
		return [[[[url path] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] lastPathComponent];
	else if (url == nil && ![title isEqualToString:NSLocalizedString (@"NEW BOOK", nil)])
		return [title stringByAppendingPathExtension:EXTENSION];
	else
		return [super displayName];
}

- (id) initWithContentsOfURL:(NSURL *) absoluteURL ofType:(NSString *) typeName error:(NSError **) outError
{
	self.fileDictionary = [NSMutableDictionary dictionary];

	NSString * path = [[[absoluteURL path] stringByAppendingPathComponent:RESOURCES] stringByAppendingPathComponent:DATAFILE];
	
	NSURL * realURL = [NSURL fileURLWithPath:path];
	
	return [super initWithContentsOfURL:realURL ofType:typeName error:outError];
}

- (BOOL) writeToURL:(NSURL *) absoluteURL ofType:(NSString *) typeName forSaveOperation:(NSSaveOperationType) saveOperation 
							 originalContentsURL:(NSURL *) absoluteOriginalContentsURL error:(NSError **) outError
{
	// CLEAN UP!!!
	
	NSFileManager * fileManager = [NSFileManager defaultManager];
	NSURL * newURL = absoluteURL;

	if (absoluteOriginalContentsURL == nil)
	{
		newURL = [NSURL fileURLWithPath:[[[absoluteURL path] stringByAppendingPathComponent:RESOURCES] stringByAppendingPathComponent:DATAFILE]];

		NSString * path = [[absoluteURL path] stringByAppendingPathComponent:RESOURCES];

		if (![fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL])
			return NO;
	}
	else if(![[absoluteURL path] hasSuffix:DATAFILE])
		newURL = [NSURL fileURLWithPath:[[[absoluteURL path] stringByAppendingPathComponent:RESOURCES] stringByAppendingPathComponent:DATAFILE]];

	BOOL hasThumbnail = NO;

	if (book.coverImage != nil)
	{
		NSString * path = [absoluteURL path];
		
		if ([path hasSuffix:DATAFILE])
			path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
		
		path = [path stringByAppendingPathComponent:QUICKLOOK];
		
		if ([fileManager fileExistsAtPath:path])
			[fileManager removeFileAtPath:path handler:nil];

		[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL];

		NSImage * previewImage = [[NSImage alloc] initWithData:self.book.coverImage];
			
		NSBitmapImageRep * imageRep = [NSBitmapImageRep imageRepWithData:[previewImage TIFFRepresentation]];
			
		NSData * previewData = [imageRep representationUsingType:NSPNGFileType properties:nil];
			
		[previewData writeToFile:[path stringByAppendingPathComponent:THUMBNAIL] atomically:YES];
			
		[previewImage release];
		
		hasThumbnail = YES;
	}
	
	for (NSString * key in [self.fileDictionary allKeys])
	{
		NSString * path = [absoluteURL path];
		
		if ([path hasSuffix:DATAFILE])
			path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];

		path = [path stringByAppendingPathComponent:RESOURCES];
		
		if (![fileManager fileExistsAtPath:path])
			[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL];
		
		NSData * fileData = [self.fileDictionary valueForKey:key];
		
		[fileData writeToFile:[path stringByAppendingPathComponent:key] atomically:YES];
		
		[self.fileDictionary removeObjectForKey:key];
	}
	
	if (!hasThumbnail)
	{
		NSString * path = [absoluteURL path];
		
		if ([path hasSuffix:DATAFILE])
			path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
		
		path = [path stringByAppendingPathComponent:QUICKLOOK];
		
		if ([fileManager fileExistsAtPath:path])
			[fileManager removeFileAtPath:path handler:nil];
		
		[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:NULL];
	}
	
	if (YES)
	{
		NSString * path = [absoluteURL path];
		
		if ([path hasSuffix:DATAFILE])
			path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
		
		path = [path stringByAppendingPathComponent:RESOURCES];

		BOOL isDirectory = NO;
		
		if ([fileManager fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory)
		{
			NSString * quicklook = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:QUICKLOOK];
			
			NSMutableArray * files = [NSMutableArray arrayWithArray:[fileManager directoryContentsAtPath:path]];
			
			[files removeObject:DATAFILE];
			
			long largest = 0;

			NSString * largestFile = nil;
			
			for (NSString * file in files)
			{
				NSDictionary * fileAttributes = [fileManager fileAttributesAtPath:[path stringByAppendingPathComponent:file] traverseLink:YES];
				
				NSNumber * bytesSize = [fileAttributes valueForKey:NSFileSize];
				
				long fileSize = [bytesSize longValue];
				
				if (fileSize > largest)
				{
					largestFile = file;
					largest = fileSize;
				}
			}
			
			if (largestFile != nil)
			{
				NSString * extension = [largestFile pathExtension];
				
				NSString * src = [[NSString stringWithFormat:@"../%@", RESOURCES, nil] stringByAppendingPathComponent:largestFile];
				NSString * filename = [NSString stringWithFormat:@"Preview.%@", extension];
				NSString * dest = [quicklook stringByAppendingPathComponent:filename];
				NSError * error = nil;
				
				[fileManager createSymbolicLinkAtPath:dest withDestinationPath:src error:&error];
				
				if (!hasThumbnail)
				{
					filename = [NSString stringWithFormat:@"Thumbnail.%@", extension];
					dest = [quicklook stringByAppendingPathComponent:filename];
					
					[fileManager createSymbolicLinkAtPath:dest withDestinationPath:src error:&error];
				}
			}
		}
	}

	return [super writeToURL:newURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:outError];
}

- (NSString *) windowNibName 
{
    return @"BookDocument";
}

- (void) updateSummaryPane
{
	NSRect topFrame = [self.contributors frame];
	CGFloat top = topFrame.origin.y + topFrame.size.height;

	/* Contributors */
	
	[self.contributors setObjectValue:[self.book valueForKey:@"contributorsString"]];
	
	[self.contributors sizeToFit];

	NSRect contributorsFrame = [self.contributors frame];
	CGFloat width = contributorsFrame.size.width;
	
	contributorsFrame.size.width = SUMMARY_FIELD_WIDTH;

	if (width > SUMMARY_FIELD_WIDTH)
	{
		NSInteger rows = (((NSInteger) width) / SUMMARY_FIELD_WIDTH) + 1;
		
		contributorsFrame.size.height = ROW_HEIGHT * rows;
	}
	else
		contributorsFrame.size.height = ROW_HEIGHT;
	
	contributorsFrame.origin.y = top - contributorsFrame.size.height;
	[self.contributors setFrame:contributorsFrame];
	
	/* Genres */

	[self.genres setObjectValue:[self.book valueForKey:@"genres"]];
	[self.genres sizeToFit];

	NSRect genresFrame = [self.genres frame];
	width = genresFrame.size.width;
	genresFrame.size.width = SUMMARY_FIELD_WIDTH;
	
	if (width > SUMMARY_FIELD_WIDTH)
	{
		NSInteger rows = (((NSInteger) width) / SUMMARY_FIELD_WIDTH) + 1;
		
		genresFrame.size.height = ROW_HEIGHT * rows;
	}
	else
		genresFrame.size.height = ROW_HEIGHT;
	
	genresFrame.origin.y = contributorsFrame.origin.y - genresFrame.size.height - 8;
	[self.genres setFrame:genresFrame];

	NSRect genresLabelFrame = [self.genresLabel frame];
	genresLabelFrame.origin.y = genresFrame.origin.y + (genresFrame.size.height - genresLabelFrame.size.height);
	[self.genresLabel setFrame:genresLabelFrame];
	
	/* Keywords */
	
	[self.keywords setObjectValue:[self.book valueForKey:@"keywords"]];
	[self.keywords sizeToFit];
	
	NSRect keywordsFrame = [self.keywords frame];
	width = keywordsFrame.size.width;
	keywordsFrame.size.width = SUMMARY_FIELD_WIDTH;
	
	if (width > SUMMARY_FIELD_WIDTH)
	{
		NSInteger rows = (((NSInteger) width) / SUMMARY_FIELD_WIDTH) + 1;
		
		keywordsFrame.size.height = ROW_HEIGHT * rows;
	}
	else
		keywordsFrame.size.height = ROW_HEIGHT;
	
	keywordsFrame.origin.y = genresFrame.origin.y - keywordsFrame.size.height - 8;
	[self.keywords setFrame:keywordsFrame];
	
	NSRect keywordsLabelFrame = [self.keywordsLabel frame];
	keywordsLabelFrame.origin.y = keywordsFrame.origin.y + (keywordsFrame.size.height - keywordsLabelFrame.size.height);
	[self.keywordsLabel setFrame:keywordsLabelFrame];
	
	/* Status */

	NSRect statusFrame = [self.status frame];
	statusFrame.origin.y = keywordsFrame.origin.y - statusFrame.size.height - 8;
	[self.status setFrame:statusFrame];
	
	NSRect statusLabelFrame = [self.statusLabel frame];
	statusLabelFrame.origin.y = statusFrame.origin.y;
	[self.statusLabel setFrame:statusLabelFrame];

	NSRect firstLineFrame = [self.firstLine frame];

	NSRect coverFrame = [self.coverBox frame];
	
	if (coverFrame.origin.y > statusFrame.origin.y)
		firstLineFrame.origin.y = statusFrame.origin.y - 9;
	else
		firstLineFrame.origin.y = coverFrame.origin.y - 9;
	
	[self.firstLine setFrame:firstLineFrame];
	
	[self.tabs setNeedsDisplay:YES];
}

- (void) windowControllerDidLoadNib:(NSWindowController *) windowController 
{
	[NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehavior10_4];
	
    [super windowControllerDidLoadNib:windowController];
	
	NSManagedObjectContext * context = [self managedObjectContext];
	NSEntityDescription * entityDescription = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:context];
	
	NSFetchRequest * request = [[[NSFetchRequest alloc] init] autorelease];
	[request setEntity:entityDescription];
	
	NSError * error = nil;
	
	NSArray * array = [context executeFetchRequest:request error:&error];
	
	if (array == nil)
		NSLog (@"error = %@", error);
	else if ([array count] == 0)
	{
		[context lock];
		
		self.book = [[BookManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
		
		[self.book setValue:NSLocalizedString (@"NEW BOOK", nil) forKey:@"title"];
		
		[context unlock];
	}	
	else
		self.book = [array lastObject];
	
	NSString * path = [[self fileURL] path];
	
	if ([path hasSuffix:DATAFILE])
		path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
	
	path = [[path stringByAppendingPathComponent:QUICKLOOK] stringByAppendingPathComponent:THUMBNAIL];
	
	[self.book willChangeValueForKey:@"coverImage"];
	self.book.coverImage = [NSData dataWithContentsOfFile:path];
	[self.book didChangeValueForKey:@"coverImage"];
	
	NSDateFormatter * dateFormatter = [[[NSDateFormatter alloc] initWithDateFormat:@"%B %1d, %Y" allowNaturalLanguage:YES] autorelease];
	
	[self.published setFormatter:dateFormatter];
	[self.started setFormatter:dateFormatter];
	[self.finished setFormatter:dateFormatter];

	[self.book addObserver:self forKeyPath:@"contributorsString" options:NSKeyValueChangeSetting context:NULL];
	[self.book addObserver:self forKeyPath:@"genres" options:NSKeyValueChangeSetting context:NULL];
	[self.book addObserver:self forKeyPath:@"keywords" options:NSKeyValueChangeSetting context:NULL];
	[self.book addObserver:self forKeyPath:@"status" options:NSKeyValueChangeSetting context:NULL];
	[self.book addObserver:self forKeyPath:@"rating" options:NSKeyValueChangeSetting context:NULL];
	[self.book addObserver:self forKeyPath:@"contributors" options:NSKeyValueChangeSetting context:NULL];

	[self updateSummaryPane];
}

- (void) observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *)context
{
	[self updateSummaryPane];

	// [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

- (NSString *) addFile:(NSString *) path
{
	NSData * fileData = [NSData dataWithContentsOfFile:path];
	
	[self.fileDictionary setValue:fileData forKey:[path lastPathComponent]];

	[self saveDocument:self];
	
	return [path lastPathComponent];
}

- (NSString *) pathForFile:(NSString *) file
{
	NSString * path = [[self fileURL] path];
	
	if ([path hasSuffix:DATAFILE])
		path = [[path stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
	
	path = [[path stringByAppendingPathComponent:RESOURCES] stringByAppendingPathComponent:file];

	if ([[NSFileManager defaultManager] fileExistsAtPath:path])
		return path;
	else
		return nil;
}

- (BOOL) removeFile:(NSString *) path
{
	NSString * fullPath = [self pathForFile:path];
	
	BOOL success = [[NSFileManager defaultManager] removeFileAtPath:fullPath handler:nil];
	
	[self saveDocument:self];
	
	return success;
}


@end
